// 绘制验证码
// 绘制尺寸  支持  px 与 rpx
// 参数字典
/* configParams={
    // 指定绘制类型
    // 默认全部  包括 数字[0-9] 英文 [a-zA-Z]  
    type, // String -> "all" | "number" |  "string"
    // 指定绘制 value 
    value, // String length == 4
    width, // Number || String #requird -> 100 |  "100px" | "100rpx"  
    height, // 同上
    // 绘制canvas id
    id, // String #requird
}   
    函数返回一个 value值  作为判断
*/
// 示例
/* 
   <template>
    <view class="content">
        <canvas
            :style="{width: verifyOpts.width ,height: verifyOpts.height }"  
            :canvas-id=" verifyOpts.id " 
            @click="updateVerifyCode"
        ></canvas>
    </view>
  </template>

<script>
import verifyCodeClass from "@/plugins/verifyCode"
	export default {
		data() {
			return {
				verifyOpts:{
					id:"verifyCode"
					,width:"150px"
					,height: "50px"
					// ,value:"1234"
				}
				,verifyCodeIntance: null
			}
		},
		mounted() {
 			this.verifyCodeIntance = new verifyCodeClass( this.verifyOpts )
        	console.log("绘制验证码 code" , this.verifyCodeIntance.getCode()  )
		},
		methods: {
			updateVerifyCode(){
				this.verifyCodeIntance.update()
				console.log("绘制验证码 code" , this.verifyCodeIntance.getCode()  )
			}
		}
	}
</script>
    

*/

/* 
    返回一个绘制字符串
    可以在 then res 第一个参数拿到 绘制字符串 执行回调函数
    verifyCode(configParams:Object);
*/
export default function verifyCode(configParams) {
  this.type = "all"
  this.code = ""
  this.width = 120
  this.height = 60
  this.ctx = null
  this.codeData = [
    "abcefghjklmnpqrstwxyABCEFGHJKLMNPQRSTWXY",
    "0123456789",
  ]
  if (configParams) {
    Object.assign(this, configParams);
    if( this.id ){
      this.init()
    }else{
      throw Error("Missing required param id")
    }
  }
}

Object.assign(verifyCode.prototype, {
  init(id) {
    return new Promise((resolve, reject) => {
      if (id) {
        this.id = id;
      }
      if (this.id) {
        let canVal;
        let drawData;
         this.ctx = this.ctx || uni.createCanvasContext(this.id);
        
        // 如果value参数没有  最常见的情况
        // 判断value 转换一组渲染字符串数组
        // 根据类型获取绘制数组
        // 没有指定value存在的情况
        if (!this.value) {
          let sliceData;
          if (this.type == "all") {
            sliceData = this.codeData.join("");
          } else if (this.type == "number") {
            sliceData = this.codeData[1];
          } else if (this.type == "string") {
            sliceData = this.codeData[0];
          } else {
            throw new Error("the type is must be all,number or string");
          }
          drawData = this.filterData(sliceData);
          // 有指定value
        } else {
          if (this.value && typeof this.value == "string" && this.value.length == 4) {
            drawData = this.filterData(this.value, false);
          } else {
            throw new Error(
              "the value params type must be string and length == 4"
            );
          }
        }
        // 判断 width 或者 height是否存在rpx单位
        // 有则根据 缩放比例计算实际宽高

        let scale = 1;
        if ((this.width + this.height).search("rpx") != -1) {
          let { windowWidth } = uni.getSystemInfoSync();
          scale = windowWidth / 750;
        }
        // 暂且只支持整数
        // 根据缩放比例重新计算宽高尺寸
        let scaleSize = function (size) {
          let num = parseInt(size);
          if (size.search("rpx") != -1) {
            return num * scale;
          }
          return num;
        };
        let drawWidth = scaleSize(this.width);
        let drawHeight = scaleSize(this.height);
        /**绘制背景色**/
        //颜色若太深可能导致看不清
        this.ctx.fillStyle = this.randomColor(180, 240);
        this.ctx.fillRect(0, 0, drawWidth, drawHeight);
        /**绘制文字**/
        for (let i = 0; i < 4; i++) {
          let ti = drawData[i],
            x = drawWidth / 4 / 10 + i * (drawWidth / 4),
            y = this.randomNum(
              drawHeight - drawHeight / 5,
              drawHeight - drawHeight / 10
            ),
            deg = this.randomNum(-20, 20);
          this.ctx.fillStyle = this.randomColor(50, 120); //随机生成字体颜色
          this.ctx.font = this.randomNum(20, drawHeight) + "px SimHei"; //随机生成字体大小
          //修改坐标原点和旋转角度
          let transX = i ? x : 0;
          this.ctx.translate(transX, y);
          this.ctx.rotate((deg * Math.PI) / 180);
          this.ctx.fillText(ti, drawWidth / 4 / 4, 0);

          //恢复坐标原点和旋转角度
          this.ctx.rotate((-deg * Math.PI) / 180);
          this.ctx.translate(-transX, -y);
          // /**绘制干扰线**/
          this.ctx.strokeStyle = this.randomColor(120, 230);
          this.ctx.beginPath();
          this.ctx.moveTo(
            this.randomNum(0, drawWidth),
            this.randomNum(0, drawHeight)
          );
          this.ctx.lineTo(
            this.randomNum(0, drawWidth),
            this.randomNum(0, drawHeight)
          );
          this.ctx.stroke();
          canVal += ti;
        }
        // /**绘制干扰点**/
        for (let j = 0; j < 10; j++) {
          this.ctx.fillStyle = this.randomColor(0, 255);
          this.ctx.beginPath();
          this.ctx.arc(
            this.randomNum(0, drawWidth),
            this.randomNum(0, drawHeight),
            1,
            0,
            2 * Math.PI
          );
          this.ctx.fill();
        }
        // 绘制完成
        this.ctx.draw();
        // 返回 绘制字符串
        let drawStr = drawData.join("");
        this.code = drawStr;
        resolve(drawStr);
      } else {
        throw Error("messing the params id");
      }
    });
  },
  update() {
    if( this.ctx ){
      this.init()
    }
  },
  getCode() {
    return this.code;
  },
  // 返回一个随机数

  randomNum(min, max) {
    return Math.floor(Math.random() * (max - min) + min);
  },
  // 返回一个随机色

  randomColor(min, max) {
    let r = this.randomNum(min, max),
      g = this.randomNum(min, max),
      b = this.randomNum(min, max);
    return `rgb(${r},${g},${b})`;
  },

  filterData(str, rdm = true) {
    let data = [];
    if (rdm) {
      let len = str.length - 1;
      for (let i = 0; i < 4; i++) {
        data.push(str[this.randomNum(0, len)]);
      }
    } else {
      data = Array.prototype.slice.call(str);
    }
    return data;
  },
});
